#!/usr/bin/env python
# -*- coding: UTF-8 -*-
"""
       Title: Port to newforms-admin
     Project: Developer tools
      Author: Will Hardy (http://willhardy.com.au)
        Date: June 2008
       Usage: ./manage.py port2nfa > admin.py

       To do: * inline classes
              * prepopulate_from

"""

import sys
from django.db import models
from django.core.management.base import BaseCommand
from django import utils
from django.contrib import admin

# Redefine repr to be able to handle proxy objects within lists, tuples and dicts
_python_repr = repr
def repr(obj):
    if isinstance(obj, list):
        return u"[%s]" % ", ".join([ repr(item) for item in obj ])
    elif isinstance(obj, tuple):
        return u"(%s, )" % ", ".join([ repr(item) for item in obj ])
    elif isinstance(obj, dict):
        items = []
        for key, value in obj.items():
            items.append(u"%s: %s" % (repr(key), repr(value)))
        return "{%s}" % ", ".join(items)
    elif obj.__class__.__name__  == "__proxy__":
        return "_(%s)" % repr(unicode(obj))
    return _python_repr(obj)


class Command(BaseCommand):
    help = 'Generates a python script to define the admin site from an oldforms admin definition..'
    args = '[appname ...]'

    def handle(self, *app_labels, **options):
        from django.db.models import get_app, get_apps, get_models

        if len(app_labels) == 0:
            app_list = get_apps()
        else:
            app_list = [get_app(app_label) for app_label in app_labels]

        # Get a list of all the relevant models
        models = []
        for app in app_list:
            models += get_models(app)

        # A dictionary to store required imports
        imports = {}

        # process the models to create a list of entries, and update the imports dictionary
        entries = get_entries(models, imports)

        # Structure the full output
        lines = Lines()
        lines += 'from django.contrib import admin'
        lines += 'from django.utils.translation import ugettext_lazy as _'
        lines += get_import_lines(imports)

        lines.add_empty_line()
        lines += entries

        lines += "site = admin.AdminSite()"
        lines += [ "site.register(%s, %sAdmin)" % (model, model) for model in imports.keys() ]

        print lines


def get_entries(models, imports):
    entries = []

    for model in models:
        entry = "\n".join(get_model_lines(model))
        if entry:
            if model.__name__ in imports:
                sys.stderr.write("A model with this name has already been processed! Skipping %s" % model.__name__)
            else:
                entries.append(entry)
                imports[model.__name__] = model.__module__

    return entries


def get_model_lines(model):
    " Returns a newforms-admin definition and registration for this model. "

    lines = Lines()
    admin_attributes = hasattr(model, "Admin") and model.Admin or model._meta.admin
    if admin_attributes:
        lines += "class %sAdmin(admin.ModelAdmin):" % model.__name__
        lines += get_basic_fields(model, admin_attributes)
        lines += get_prepopulated_fields(model)
        if len(lines) == 1:
            lines += '    pass'
        lines.add_empty_line()

    return lines


def get_basic_fields(model, admin_attributes):
    lines = Lines()

    if hasattr(model, "Admin") and model.Admin:
        for key,value in model.Admin.__dict__.items():
            if not key.startswith("__"):
                lines += "    %s = %s" % (key, repr(value))

    if model._meta.admin:
        from django.db.models.options import AdminOptions
        default_object = AdminOptions()
        for key,value in model._meta.admin.__dict__.items():
            if value and key not in ('manager', ) and value != getattr(default_object, key):
                lines += "    %s = %s" % (key, repr(value))

    return lines


def get_prepopulated_fields(model):
    fields = {}
    for field in model._meta.fields:
        if hasattr(field, 'prepopulate_from') and field.prepopulate_from:
            fields[field.name] = field.prepopulate_from
    if fields:
        return "prepopulated_fields = %s" % repr(fields)


def get_import_lines(imports):
    " Takes a dictionary of imports and formats them nicely. "

    # Create a dictionary to combine imported objects from the same module
    imports_dict = {}
    for key,value in imports.items():
        if value in imports_dict:
            imports_dict[value].append(key)
        else:
            imports_dict[value] = [key]

    # Generate the final formatted output
    return [ 'from %s import %s' % (mod, ", ".join(obj)) for mod,obj in imports_dict.items() ]



# HELPER CLASSES
################################################################################

class Lines(list):
    def add_empty_line(self):
        self.append("")

    def add_line(self, value):
        self.append(value)

    def __unicode__(self):
        return u"\n".join(self)

    def __str__(self):
        return "\n".join(self)

    def __iadd__(self, value):
        if isinstance(value, basestring):
            value = [ value ]
        if value:
            return super(Lines, self).__iadd__(value)
        else:
            return self
